﻿#include"stdafx.h"
#ifdef LK_REFLECTION_
namespace LK
{
	namespace Reflection
	{
		bool PFunctionNode::AddFunction(Functional::PFunObjs fun)const { return AddFunction(fun, Convert<PDomainNode, PObject>::RefFrom(PObject())); }
		bool PFunctionNode::AddFunction(Functional::PFunObjs fun, PDomainNode domain)const
		{
			return Ptr()->AddFunction(fun, domain);
		}
		bool PFunctionNode::AddOperatorFunction(Functional::PFunObjs fun)const
		{
			return Ptr()->AddOperatorFunction(fun);
		}
		/**
		@brief 动态传参并调用方法
		@note 该方法在找不到合适的重载时会抛出FunctionOverloadNotFoundException*/
		PObject PFunctionNode::DynamicCall(PObject const& obj, Collection::PArray<PObject>args)const
		{
			Collection::PArray<PType>targs(args.size());
			for (index_t i = 0; i < args.size(); ++i)
			{
				targs[i] = args[i].GetType();
				if (targs[i] == PType::Make<PMObjects>())
					targs[i] = ((PMObjects&)args[i]).GetInnerType();
			}
			Functional::PFunObjs f = GetFunction(targs);
			if(f.IsNull())
				throw PFunctionOverloadNotFoundException();
			return f.Call(obj, args);
		}
		/**
		@brief 动态传入参数类型以获取调用的重载版本
		@param [传入，可省]参数isExplicit用以指示是否精确匹配，默认为false
		@note 该方法在找不到合适的重载时会返回NULL*/
		Functional::PFunObjs PFunctionNode::GetFunction(Collection::PArray<PType>args, bool isExplicit)const
		{
			return Ptr()->GetFunction(args,isExplicit);
		}

		/**
		@brief 动态传入参数类型以获取调用的重载版本
		@param [传入，可省]参数isExplicit用以指示是否精确匹配，默认为false
		@note 该方法在找不到合适的重载时返回NULL*/
		Functional::PFunObjs FunctionNode::GetFunction(Collection::PArray<PType>t,bool isExplicit)const
		{
			index_t i = Methods.DichotomyIndexOf(t, &FunctionNode::ConstructCompare);
			if (i >= 0)
			{
				if (t.IsNull() || t.size() == 0)return Methods[i];
				Collection::PArray<PType> tarr;
				bool bf = false;
			ReFind:;
				tarr = Methods[i].GetArgsType();
				index_t cmp = (tarr.size() < t.size() + 2) ? -1 : (tarr.size() > t.size() + 2) ? 1 : 0;
				index_t rcmp = cmp;
				if (cmp == 0)for (index_t k = 0; k < t.size(); ++k)
				{
					rcmp = tarr[k + 2].CompareWithoutExtents(t[k]);
					if (cmp == 0)cmp = tarr[k + 2].CompareWith(t[k]);
					if (rcmp != 0) { cmp = rcmp; break; }
				}
				if (i > 0 && cmp>0) { i--; bf = true; if (rcmp == 0)goto ReFind; }
				else if (i < Methods.size() && cmp<0) { i++; if (!bf&&rcmp == 0)goto ReFind; }
				return Methods[i];
			}
			//找不到将进行模糊查询
			for (i = 0; i < Methods.size(); ++i)
			{
				Collection::PArray<PType> tarr = Methods[i].GetArgsType();
				index_t cmp = (tarr.size() < t.size() + 2) ? -1 : (tarr.size() > t.size() + 2) ? 1 : 0;
				if (cmp == 0)
				{
					index_t k;
					for (k = 0; k < t.size(); ++k)
						if (!tarr[k + 2].CanDynamicConvertFrom(t[k],isExplicit?0:1))break;
					if (k == t.size())return Methods[i];
				}
			}
			return Functional::PFunObjs();
		}

		FunctionNode::FunctionNode(PString const& name, WeakPtr<PTypeLibrary> const&  library, PDomainNode const& baseNode)
			:InDomain(false),LibraryNode(library, baseNode, name) {}
		bool FunctionNode::AddFunction(Functional::PFunObjs fun){return AddFunction(fun,Convert<PDomainNode,PObject>::RefFrom(PObject()));}
		bool FunctionNode::AddFunction(Functional::PFunObjs fun, PDomainNode domain)
		{
			if (fun.IsNull())throw PInvalidArgumentException(L"传入的函数为空");
			if (!GetBaseNode().IsNull()) {
				if (!domain.IsNull() && InDomain&&domain != GetBaseNode())return false;
				if (!InDomain && (domain.IsNull() || domain == GetBaseNode())) {
					InDomain = true;
					Methods.SetToNull();
				}
			}
			if (Methods.IsNull())
                Methods = new LK::Collection::DefaultArray<Functional::PFunObjs>();
			for (index_t i = 0; i < Methods.size(); ++i)
				if (Methods[i].Equals(fun))return false;
			Methods.DichotomyInsertAsc(fun,&FunctionNode::FunctionCompare);
			return true;
		}
		bool FunctionNode::AddOperatorFunction(Functional::PFunObjs fun)
		{
			if (fun.IsNull())throw PInvalidArgumentException(L"传入的函数为空");
			if (Methods.IsNull())Methods = new LK::Collection::DefaultArray<Functional::PFunObjs>();
			for (index_t i = 0; i < Methods.size(); ++i)
				if (Methods[i].Equals(fun))return false;
			Methods.DichotomyInsertAsc(fun, &FunctionNode::OperatorFunctionCompare);
			return true;
		}
		index_t FunctionNode::FunctionCompare(Functional::PFunObjs const&f1, Functional::PFunObjs const&f2)
		{
			Collection::PArray<PType> arr2 = f2.GetArgsType();
			return FunctionTypeCompare(f1,arr2);
		}
		index_t FunctionNode::FunctionTypeCompare(Functional::PFunObjs const&f1, Collection::PArray<PType> const&arr2)
		{
			Collection::PArray<PType> arr1 = f1.GetArgsType();
			if (arr1.size() != arr2.size())return arr1.size()>arr2.size() ? 1 : -1;
			if (arr1.size() == 2)return 0;
			for (index_t i = 2; i < arr1.size(); ++i)
			{
				index_t cmp = arr1[i].CompareWithoutExtents(arr2[i]);
				if (cmp != 0)return cmp;
			}
			for (index_t i = 2; i < arr1.size(); ++i)
				if (arr1[i].GetPtr()->attr != arr2[i].GetPtr()->attr)return arr1[i].GetPtr()->attr - arr2[i].GetPtr()->attr;
			return 0;
		}
		index_t FunctionNode::OperatorFunctionCompare(Functional::PFunObjs const&f1, Functional::PFunObjs const&f2)
		{
			Collection::PArray<PType> arr1 = f1.GetArgsType();
			Collection::PArray<PType> arr2 = f2.GetArgsType();
			if (arr1.size() != arr2.size())return arr1.size()>arr2.size() ? 1 : -1;
			index_t cmp = arr1[0].CompareWithoutExtents(arr2[0]);
			if (cmp != 0)return cmp;
			if (arr1[0].GetPtr()->attr != arr2[0].GetPtr()->attr)return arr1[0].GetPtr()->attr - arr2[0].GetPtr()->attr;
			return 0;
		}
		index_t FunctionNode::ConstructCompare(Functional::PFunObjs const&f1, Collection::PArray<PType> const&arr2)
		{
			Collection::PArray<PType> arr1 = f1.GetArgsType();
			if (arr1.size() != (arr2.IsNull()?2:arr2.size()+2))return arr1.size()>(arr2.IsNull() ? 2 : arr2.size() + 2) ? 1 : -1;
			if (arr1.size() == 2)return 0;
			for (index_t i = 0; i < arr1.size(); ++i)
			{
				index_t cmp = arr1[i + 2].CompareWithoutExtents(arr2[i]);
				if (cmp!=0)return cmp;
			}
			return 0;
		}
		index_t FunctionNode::OperatorCompare(Functional::PFunObjs const&t1, PType const&t2)
		{
			return t1.GetArgsType()[0].CompareWithoutExtents(t2);
		}
	}
}
#endif
